﻿using System;
using System.Collections;
using System.Collections.Specialized;
using System.Reflection;

namespace Core.Tools
{
    public class NameValueDictionary : IDictionary, IConvertible
    {
        private static readonly Func<NameValueCollection, string, object> BaseGet;

        static NameValueDictionary()
        {
            var BaseGetMethod = typeof(NameValueCollection).GetMethod("BaseGet", BindingFlags.Instance | BindingFlags.NonPublic, Type.DefaultBinder, new Type[] { typeof(string) }, null);

            BaseGet = (Func<NameValueCollection, string, object>)Delegate.CreateDelegate(typeof(Func<NameValueCollection, string, object>), BaseGetMethod);
        }

        public readonly NameValueCollection Content;

        public NameValueDictionary(NameValueCollection Content)
        {
            this.Content = Content;
        }

        public object this[object key]
        {
            get
            {
                return Content[(string)key];
            }
            set
            {
                Content[(string)key] = (string)value;
            }
        }

        public ICollection Values
        {
            get
            {
                return new CollectionEnumerable<string>(Index => { return Content[Index]; }, Count, true);
            }
        }

        public bool IsFixedSize { get { return false ; } }

        public int Count { get { return Content.Count; } }

        public object SyncRoot { get { return null; } }

        public bool IsSynchronized { get { return false; } }

        public ICollection Keys { get { return Content.Keys; } }

        public bool IsReadOnly { get { return false; } }

        public void Add(object key, object value)
        {
            Content.Add((string)key, (string)value);
        }

        public void Clear()
        {
            Content.Clear();
        }

        public bool Contains(object key)
        {
            return BaseGet(Content,(string)key) != null;
        }

        public void CopyTo(Array array, int index)
        {
            Content.CopyTo(array, index);
        }

        public IEnumerator GetEnumerator()
        {
            return new NameValueEnumerator(Content, true);
        }

        public void Remove(object key)
        {
            Content.Remove((string)key);
        }

        IDictionaryEnumerator IDictionary.GetEnumerator()
        {
            return new NameValueEnumerator(Content, true);
        }

        #region -- IConvertible

        TypeCode IConvertible.GetTypeCode()
        {
            return TypeCode.Object;
        }

        bool IConvertible.ToBoolean(IFormatProvider provider)
        {
            throw new InvalidCastException();
        }

        char IConvertible.ToChar(IFormatProvider provider)
        {
            throw new InvalidCastException();
        }

        sbyte IConvertible.ToSByte(IFormatProvider provider)
        {
            throw new InvalidCastException();
        }

        byte IConvertible.ToByte(IFormatProvider provider)
        {
            throw new InvalidCastException();
        }

        short IConvertible.ToInt16(IFormatProvider provider)
        {
            throw new InvalidCastException();
        }

        ushort IConvertible.ToUInt16(IFormatProvider provider)
        {
            throw new InvalidCastException();
        }

        int IConvertible.ToInt32(IFormatProvider provider)
        {
            throw new InvalidCastException();
        }

        uint IConvertible.ToUInt32(IFormatProvider provider)
        {
            throw new InvalidCastException();
        }

        long IConvertible.ToInt64(IFormatProvider provider)
        {
            throw new InvalidCastException();
        }

        ulong IConvertible.ToUInt64(IFormatProvider provider)
        {
            throw new InvalidCastException();
        }

        float IConvertible.ToSingle(IFormatProvider provider)
        {
            throw new InvalidCastException();
        }

        double IConvertible.ToDouble(IFormatProvider provider)
        {
            throw new InvalidCastException();
        }

        decimal IConvertible.ToDecimal(IFormatProvider provider)
        {
            throw new InvalidCastException();
        }

        DateTime IConvertible.ToDateTime(IFormatProvider provider)
        {
            throw new InvalidCastException();
        }

        string IConvertible.ToString(IFormatProvider provider)
        {
            throw new InvalidCastException();
        }

        object IConvertible.ToType(Type conversionType, IFormatProvider provider)
        {
            if (conversionType.IsInstanceOfType(Content))
            {
                return Content;
            }

            throw new InvalidCastException();
        }

        #endregion
    }
}